//
//  ViewHierarchy.swift
//  
//
//  Created by bo wang on 2020/10/8.
//  Copyright © 2020 wangbo. All rights reserved.
//

import Foundation
import UIKit

extension UIView {
    var dd_vc: UIViewController? {
        var next = superview
        while next != nil {
            if let nextResp = next?.next as? UIViewController {
                return nextResp
            }
            next = next?.superview
        }
        return nil
    }
    
    var dd_navi: UINavigationController? {
        return dd_vc?.navigationController
    }
    
    /// 向上找到一个最近的指定类型的父视图
    /// - Parameter cls: 类型
    /// - Returns: 符合条件的view
    func parentView<T>(of cls: T.Type) -> T? where T: UIView {
        if let x = superview as? T {
            return x
        }
        return superview?.parentView(of: cls)
    }
    
    /// 如果此View以及其父视图层级上的View中有一个 isHidden为true 或者 alpha<0.01 那么就认为这个View是hidden的
    var isRealHidden: Bool {
        if isHidden || alpha < 0.01 {
            return true
        }
        return superview?.isRealHidden ?? false
    }
}

extension UIViewController {
    
    /// 当前控制器弹出的 presentedViewController 栈，不包括当前控制器
    var presentedVCStack: [UIViewController] {
        var list: [UIViewController] = [self]
        while let v = list.last?.presentedViewController {
            list.append(v)
        }
        list.removeFirst()
        return list
    }
    
    /// 当前控制器弹出的最顶层控制器，没有弹出任何控制器时为nil
    var topPresentedVC: UIViewController? {
        presentedVCStack.last
    }
    
    /// 当前控制器被弹出时的最底层控制器
    var bottomPresentingVC: UIViewController? {
        var vc: UIViewController? = self
        while let v = vc?.presentingViewController {
            vc = v
        }
        return vc
    }
    
    var rootVC: UIViewController? {
        var vc: UIViewController? = self
        while let v = vc?.parent {
            vc = v
        }
        return vc
    }
    
    /// 找到最顶层的控制器
    var topVC: UIViewController? {
        if let navi = self as? UINavigationController {
            return navi.visibleViewController?.topVC
        } else if let tabvc = self as? UITabBarController {
            return tabvc.selectedViewController?.topVC
        } else if let vc = presentedViewController {
            return vc.topVC
        } else if !self.children.isEmpty {
            return self.children.last
        }
        return self
    }
    
    static var topVC: UIViewController? {
        return UIApplication.shared.keyWindow?.rootViewController?.topVC
    }
    
    /// 当前 present 栈中，位于 vcType 指定类型的控制器以上的所有控制器全部消失。
    /// 如果 vcType 本身已经在顶层，那么什么都不做。
    func dismissAll(until vcType: UIViewController.Type, animated: Bool = true, completion: (() -> Void)? = nil) {
        let stack = presentedVCStack
        if let targetIndex = stack.firstIndex(where: { type(of: $0) == vcType }) {
            let targetVC = stack[targetIndex]
            if targetVC !== stack.last {
                targetVC.dismiss(animated: animated, completion: completion)
            }
        }
    }
}

extension UINavigationController {
    /// pop 到 vcType 指定类型的控制器
    func popTo(vcType: UIViewController.Type, animated: Bool = true) {
        if let targetVC = viewControllers.first(where: { type(of: $0) == vcType }) {
            popToViewController(targetVC, animated: animated)
        }
    }
}

extension UIWindow {
    var topVC: UIViewController? {
        return rootViewController?.topVC
    }
}

extension UIPageViewController {
    
    var scrollView: UIScrollView? {
        view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView
    }
    
    func enableSwipeGesture() {
        scrollView?.isScrollEnabled = true
    }
    
    func disableSwipeGesture() {
        scrollView?.isScrollEnabled = false
    }
    
    /// UIScrollViewPanGestureRecognizer
    var panGestureRecognizer: UIPanGestureRecognizer? {
        scrollView?.panGestureRecognizer
    }
    
    /// 滑动返回手势和 UIpageViewController 的pan手势冲突，导致滑动返回失效。
    /// 使用此方法使滑动返回生效
    /// 应该在 viewDidAppear 中调用
    func fixGestureConflict(with naviCtrl: UINavigationController?) {
        if let popGR = naviCtrl?.interactivePopGestureRecognizer {
            panGestureRecognizer?.require(toFail: popGR)
        }
    }
}
